﻿//-----------------------------------------------------------------------
// <copyright file="Member.cs">
//     Copyright (c) Nicole Calinoiu. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
using System;
using System.Xml;
using Microsoft.FxCop.Sdk;

namespace Bordecal.FxCop.Sdk.Testing
{
	/// <summary>
	/// Represents a type member screened by FxCop.
	/// </summary>
	internal sealed class Member : Target
	{
		internal Member(Type parent, XmlElement element)
			: this((Target)parent, element)
		{
		}

		internal Member(Member parent, XmlElement element)
			: this((Target)parent, element)
		{
		}

		private Member(Target parent, XmlElement element)
			: base(parent, element)
		{
			this.NodeType = element.GetAttribute("Kind").ToEnum<NodeType>();
			this.IsStatic = bool.Parse(element.GetAttribute("Static"));
			this.IsExternallyVisible = bool.Parse(element.GetAttribute("ExternallyVisible"));
		}

		internal Member(Microsoft.FxCop.Sdk.Member member)
			: base(Member.CreateParent(member), member.Name.Name)
		{
			this.NodeType = member.NodeType;
			this.IsStatic = member.IsStatic;
			this.IsExternallyVisible = member.IsVisibleOutsideAssembly;

			this.AdjustName(member);
			this.AdjustNodeType();
		}
		
		/// <summary>
		/// Gets the <see cref="NodeType"/> of the member.
		/// </summary>
		internal NodeType NodeType { get; private set; }

		/// <summary>
		/// Gets a value indicating whether the member is static.
		/// </summary>
		internal bool IsStatic { get; private set; }

		/// <summary>
		/// Gets a value indicating whether the member may be accessed from outside its assembly.
		/// </summary>
		/// <value>
		/// </value>
		internal bool IsExternallyVisible { get; private set; }

		private static Target CreateParent(Microsoft.FxCop.Sdk.Member member)
		{
			Target result;

			var method = member as Method;
			if ((method == null) || (method.DeclaringMember == null))
			{
				result = new Type(member.DeclaringType);
			}
			else
			{
				result = new Member(method.DeclaringMember);
			}

			return result;
		}

		private void AdjustName(Microsoft.FxCop.Sdk.Member member)
		{
			var method = member as Method;
			if (method != null)
			{
				this.Name = "#" + method.GetUnmangledNameWithTypeParameters(false);
				if (method.Parameters.Count == 0)
				{
					this.Name += "()";
				}

				if (this.Name.StartsWith("##ctor(", StringComparison.Ordinal))
				{
					this.Name = "#." + this.Name.Substring(2);
				}
			}
			else if (member.NodeType == NodeType.Property)
			{
				this.Name = "#" + this.Name;
			}
		}

		private void AdjustNodeType()
		{
			switch (this.NodeType)
			{
				case NodeType.InstanceInitializer:
				case NodeType.StaticInitializer:
					this.NodeType = NodeType.Method;
					break;
			}
		}

		internal override bool Equals(Target target)
		{
			bool result = false;
			if (base.Equals(target))
			{
				Member member = (Member)target;
				if ((member.NodeType == this.NodeType) &&
					(member.IsStatic == this.IsStatic) &&
					(member.IsExternallyVisible == this.IsExternallyVisible))
				{
					result = true;
				}
			}

			return result;
		}
	}
}